package com.flaskpy.web.eternity.admin.config;

import com.alibaba.fastjson.JSONArray;
import com.flaskpy.web.eternity.core.api.ErrorResponse;
import com.flaskpy.web.eternity.core.api.R;
import com.flaskpy.web.eternity.core.exception.BizDataException;
import com.flaskpy.web.eternity.core.exception.BizException;
import com.flaskpy.web.eternity.core.exception.ExpCodeFactory;
import com.flaskpy.web.eternity.core.exception.enums.AuthExceptionEnum;
import com.flaskpy.web.eternity.core.exception.enums.BaseExceptionEnum;
import com.flaskpy.web.eternity.core.exception.enums.FailExceptionEnum;
import com.flaskpy.web.eternity.core.exception.enums.RemoteExceptionEnum;
import io.lettuce.core.RedisConnectionException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Slf4j
@RestControllerAdvice
public class GlobalExceptionConfig {
    /**
     * 空指针
     * @param ex
     * @return
     */
    @ExceptionHandler(NullPointerException.class)
    public ErrorResponse nullException(NullPointerException ex){
        log.error(String.format("收到一个空指针报错 :",ex.getStackTrace()));
        return R.error(FailExceptionEnum.NULL_EXCEPTION);
    }

    /**
     * 404
     * @param exception
     * @return
     */
    @ExceptionHandler(value = NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse handlerNoHandlerFoundException(NoHandlerFoundException exception) {
        return R.error(BaseExceptionEnum.NOT_FOUND_ERROR);
    }

    /**
     * 405
     * @param exception
     * @return
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ErrorResponse handlerHttpRequestMethodNotSupportedException(
            HttpRequestMethodNotSupportedException exception) {

        return R.error(BaseExceptionEnum.METHOD_NOT_SUPPORT);
    }

    /**
     * 业务错误
     * @param ex
     * @return
     */
    @ExceptionHandler(BizDataException.class)
    public  ErrorResponse bizDataException(BizDataException ex){
        log.warn(String.format("收到一个业务级报错 {} {}", ExpCodeFactory.generate(ex),ex.getMsg()));
        return R.error(ex.getExceptionEnum(),ex.getData());
    }

    /**
     * 业务错误（带数据）
     * @param ex
     * @return
     */
    @ExceptionHandler(BizException.class)
    public ErrorResponse bizException(BizException ex){
        log.warn(String.format("收到一个业务级报错 {} {}", ExpCodeFactory.generate(ex),ex.getMsg()));
        return R.error(ex.getExceptionEnum());
    }

    /**
     *  缺少请求参数
     * @param ex
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ErrorResponse notParamError(HttpMessageNotReadableException ex){

        return R.error(BaseExceptionEnum.PARAM_ERROR);
    }

    /**
     * 用户名或密码错误
     * @param ex
     * @return
     */
    @ExceptionHandler(BadCredentialsException.class)
    public ErrorResponse credentials(BadCredentialsException ex){
        return R.error(AuthExceptionEnum.NAME_OR_PWD_ERROR);
    }

    /**
     * 没有权限
     * @param ex
     * @return
     */
    @ExceptionHandler(AccessDeniedException.class)
    public ErrorResponse accessDeniedException(AccessDeniedException ex){
        return R.error(AuthExceptionEnum.ACCESS_FIAL);
    }
    /**
     * 参数验证错误
     * @param ex
     * @return
     */
    @ExceptionHandler(BindException.class)
    public  ErrorResponse allError1(BindException ex){
        BindingResult bindingResult = ex.getBindingResult();
        List<FieldError> fs = bindingResult.getFieldErrors();
        List<Map<String,String>> data=new ArrayList<>();
        for(FieldError e :fs){
            data.add(new HashMap<String,String>(){{ put("field",e.getField());put("msg",e.getDefaultMessage()); }});
        }
        return R.error(BaseExceptionEnum.PARAM_ERROR,data);
    }
    @ExceptionHandler(RedisConnectionFailureException.class)
    public  ErrorResponse redisConnectError(RedisConnectionFailureException ex){
        return  R.error(RemoteExceptionEnum.REDIS_CONNECT_ERROR);
    }
    /**
     * 未知异常
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ErrorResponse allError2(Exception ex){
        log.error(String.format("收到一个致命级报错 %s %s", ExpCodeFactory.generate(FailExceptionEnum.FAIL_EXCEPTION),
                ex.getMessage()));
        return R.error(FailExceptionEnum.FAIL_EXCEPTION);
    }
}
